package top.flvio.middleware.util;

import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @description: 属性工具类
 * @author: flvio
 * @date: 2025/2/3
 */
public class PropertyUtil
{
    private static int springBootVersion = 1;

    static {
        try
        {
            Class.forName("org.springframework.boot.bind.RelaxedPropertyResolver");
        }catch (ClassNotFoundException e){
            springBootVersion = 2;
        }
    }

    public static <T> T handle(final Environment environment,final String prefix, final Class<T> targetClass){
        switch (springBootVersion){
            case 1:
                return (T) v1(environment,prefix);
            default:
                return (T) v2(environment,prefix,targetClass);
        }
    }

    private static Object v1(final Environment environment, final String prefix) {
        try {
            Class<?> resolverClass = Class.forName("org.springframework.boot.bind.RelaxedPropertyResolver");
            Constructor<?> resolverConstructor = resolverClass.getDeclaredConstructor(PropertyResolver.class);
            Method getSubPropertiesMethod = resolverClass.getDeclaredMethod("getSubProperties", String.class);
            Object resolverObject = resolverConstructor.newInstance(environment);
            String prefixParam = prefix.endsWith(".") ? prefix : prefix + ".";
            return getSubPropertiesMethod.invoke(resolverObject, prefixParam);
        } catch (final ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
                | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

    private static Object v2(final Environment environment,final String prefix,final Class<?> targetClass){
        try
        {
            Class<?> bindClass = Class.forName("org.springframework.boot.context.properties.bind.Binder");
            Method getMethod = bindClass.getDeclaredMethod("get",Environment.class);
            Method bindMethod = bindClass.getDeclaredMethod("bind",String.class,Class.class);
            Object bindObject = getMethod.invoke(null, environment);
            String prefixParam = prefix.endsWith(".") ? prefix.substring(0,prefix.length() - 1) : prefix;
            Object bindResultObject = bindMethod.invoke(bindObject, prefixParam, targetClass);
            Method resultGetMethod = bindResultObject.getClass().getDeclaredMethod("get");
            return resultGetMethod.invoke(bindResultObject);

        }catch (final ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException ex) {
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

}
